import { getUtf8String, getUtf8Bytes } from '../byte/charset'

const encodeCharCount = 64
// js代码加密，参考：https://www.sojson.com/javascriptobfuscator.html
const dic = [
  'r', 'x', 'm', 'E', '-', 'I', 'V', '/',
  'C', 'e', 's', '>', '!', '4', '2', 'P',
  'l', 'K', '.', 'H', 'a', 'R', '|', 'J',
  '+', '~', 'A', '0', 'z', '}', 'Q', '(',
  '^', '?', ';', 'o', 't', 'M', '%', 'u',
  '*', 'D', 'g', ')', 'T', 'S', 'w', 'U',
  'v', 'f', 'N', 'L', 'F', 'O', '@', 'j',
  '_', 'p', '7', '{', 'W', 'd', 'k', 'b',
  '3', '=', '5', 'c', 'i', '`', 'q', '[',
  'Z', 'y', ']', 'h', 'G', ':', 'B', '8',
  '1', 'X', '&', 'n', '$', '#', '9', '<',
  '6', 'Y'
]

const offsetDic: Record<string, number> = {}
const offsetDecodeDic: Record<string, number>[] = []

for (let i = 0; i < dic.length; i++) {
  offsetDic[dic[i]] = i
}

for (let i = 0; i < dic.length; i++) {
  const decodeDic: Record<string, number> = {}
  for (let j = 0; j < encodeCharCount; j++) {
    const index = (i + j) % dic.length
    decodeDic[dic[index]] = j
  }
  offsetDecodeDic[i] = decodeDic
}

export function dataEncode(src: string) {
  const bytes = getUtf8Bytes(src)
  const dicLength = dic.length
  const dicOffset = Math.round((dicLength - 1) * Math.random())
  const sLength = bytes.length
  const dst = [dic[dicOffset]]
  const end3 = ~~(sLength / 3) * 3 // 先编码 3 * 8 => 4 * 6
  let sp = 0 // 源串指针
  let dp = 1 // 目标串指针
  while (sp < end3) {
    const bits = (bytes[sp++] & 0xff) << 16 | (bytes[sp++] & 0xff) << 8 | (bytes[sp++] & 0xff)
    dst[dp++] = dic[(dicOffset + ((bits >>> 18) & 0x3f)) % dicLength]
    dst[dp++] = dic[(dicOffset + ((bits >>> 12) & 0x3f)) % dicLength]
    dst[dp++] = dic[(dicOffset + ((bits >>> 6) & 0x3f)) % dicLength]
    dst[dp++] = dic[(dicOffset + (bits & 0x3f)) % dicLength]
  }
  if (sp < sLength) { // 1 or 2 leftover bytes(1~16bits)
    const b0 = bytes[sp++] & 0xff
    dst[dp++] = dic[(dicOffset + (b0 >> 2)) % dicLength]
    if (sp === sLength) {
      dst[dp] = dic[(dicOffset + ((b0 << 4) & 0x3f)) % dicLength]
    } else {
      const b1 = bytes[sp] & 0xff
      dst[dp++] = dic[(dicOffset + (((b0 << 4) & 0x3f) | (b1 >> 4))) % dicLength]
      dst[dp] = dic[(dicOffset + ((b1 << 2) & 0x3f)) % dicLength]
    }
  }
  return dst.join('')
}

export function dataDecode(src: string) {
  const dicOffset = offsetDic[src[0]]
  if (dicOffset < 0) {
    throw new Error('Illegal offset ,src = ' + String(src))
  }
  const decodeDic = offsetDecodeDic[dicOffset]
  let dp = 0
  let sp = 1
  const end = src.length
  const dst:number[] = []
  const end4 = ~~((src.length - 1) / 4) * 4 // 先编码 3 * 8 => 4 * 6
  while (sp < end4) {
    const b0 = decodeDic[src[sp++]]
    const b1 = decodeDic[src[sp++]]
    const b2 = decodeDic[src[sp++]]
    const b3 = decodeDic[src[sp++]]
    if (b0 === undefined || b1 === undefined || b2 === undefined || b3 === undefined) {
      throw new Error('Illegal char ,src = ' + String(src))
    }
    const bits = b0 << 18 | b1 << 12 | b2 << 6 | b3
    dst[dp++] = ((bits & 0xFF0000) >> 16)
    dst[dp++] = ((bits & 0xFF00) >> 8)
    dst[dp++] = bits & 0xFF
  }
  if (sp < end) {
    if (sp + 2 === end) {
      const b0 = decodeDic[src[sp++]]
      const b1 = decodeDic[src[sp]]
      if (b0 === undefined || b1 === undefined) {
        throw new Error('Illegal char ,src = ' + String(src))
      }
      dst[dp] = (b0 << 2 | b1 >> 4)
    } else if (sp + 3 === end) {
      const b0 = decodeDic[src[sp++]]
      const b1 = decodeDic[src[sp++]]
      const b2 = decodeDic[src[sp]]
      if (b0 === undefined || b1 === undefined || b2 === undefined) {
        throw new Error('Illegal char ,src = ' + String(src))
      }
      dst[dp++] = (b0 << 2 | b1 >> 4)
      dst[dp] = ((b1 & 0b1111) << 4 | b2 >> 2)
    } else {
      throw new Error('Illegal bits, src = ' + String(src))
    }
  }
  return getUtf8String(dst)
}
